﻿module Main where

import Data.Graph.Inductive.Tree (UGr, Gr)
import Maybe (fromMaybe)
import Data.Graph.Inductive.Example (labUEdges)
import Data.Graph.Inductive.Graph (mkGraph, UEdge, lab, nodes, edges, isEmpty)
import System (getArgs)
import System.Console.GetOpt
import Random (mkStdGen, randomR, StdGen, next, getStdGen, next)
import List (find)
import Coloring (color, check_colors)
import Dot (dot_string_to_graph, graph_to_dot_string)
import Utils (first_of_three, second_of_three, third_of_three)
import System.CPUTime (getCPUTime)

--Generates random unlabeled graph with given number of edges and random base
generate_random_graph :: Int -> Int -> UGr
generate_random_graph n start = mkGraph [(x,()) | x <- [1..n]] $ generate_random_edges (mkStdGen start) (n,n-1) [] where
	rnd = randomR (0,1)
	generate_random_edges :: StdGen -> (Int,Int) -> [(Int,Int)] -> [UEdge]
	generate_random_edges _ (0,_) = labUEdges
	generate_random_edges gen (first,0)= generate_random_edges gen (first-1,first-2)
	generate_random_edges gen (first,second)=
		case rnd gen of
			(val,newGen) -> generate_random_edges 
								newGen 
								(first,second-1) 
								.if val == (0::Int) then id else \lst -> (first,second):(second,first):lst

graph_to_string :: (Show a) => Gr a () -> String
graph_to_string gr =
	foldl (\str (start,end)-> if start <= end then concat [str, show start, " - ", show end, "\n"] else str) 
		  	((foldl (\str node -> concat [str, show node, " ", case (lab gr node) of 
																	Just a -> "Color: " ++ (show a)
																	Nothing -> "", "\n"]) 
					"Vertexes:\n" 
					(nodes gr)) ++ "\nEdges:\n")
		  $ edges gr

gr_plus_trace x n str
	|n == 0 = color $ dot_string_to_graph str
	|otherwise = color $ generate_random_graph n $ fst $ next x
	
to_ms_time :: Integer -> Integer
to_ms_time time = time `div` 1000000
				   
--Main function	
main :: IO ()	
main = do
	cmdParam <- getArgs
	case getOpt RequireOrder options cmdParam of
		(flags, [],[]) -> 
			case find_fun flags of
			(Nothing,Nothing,Nothing) -> to_do dEFAULT_IN_FILE dEFAULT_OUT_FILE dEFAULT_VERTEX_NUMBER
			(_,Nothing,Just (Numb num)) -> to_do dEFAULT_IN_FILE dEFAULT_OUT_FILE $ read num
			(_,Just (Output outFile),Just (Numb num)) -> to_do dEFAULT_IN_FILE outFile $ read num
			(Nothing,Just (Output outFile),_) -> to_do dEFAULT_IN_FILE outFile dEFAULT_VERTEX_NUMBER
			(Just (Input inFile),Nothing,_) -> to_do inFile dEFAULT_OUT_FILE 0
			(Just (Input inFile),Just (Output outFile),_) -> to_do inFile outFile 0
			(_,_,_) -> error "Error. Invalid flags\n"
			where
				find_fun flags = 
					(find (\flag -> case flag of 
									Input _ -> True
									_ -> False) flags,
					find (\flag -> case flag of
									Output _ -> True
									_ -> False) flags, 
					find (\flag -> case flag of
									Numb _ -> True
									_ -> False) flags)
		(_,nonOpts,[]) -> to_do dEFAULT_IN_FILE dEFAULT_OUT_FILE dEFAULT_VERTEX_NUMBER
		(_, _,msgs) -> to_do dEFAULT_IN_FILE dEFAULT_OUT_FILE dEFAULT_VERTEX_NUMBER
		where
			dEFAULT_IN_FILE = "in.dot"
			dEFAULT_OUT_FILE = "out.dot"
			dEFAULT_VERTEX_NUMBER = 10
	
to_do :: String -> String -> Int -> IO ()
to_do inFile outFile num = do 
	x <- getStdGen
	grStr <- if num == 0 then readFile inFile else return ""
	gpt <- return $ gr_plus_trace x num grStr
	graph <- return $ first_of_three gpt
	trace <- return $ second_of_three gpt
	number <- return $ third_of_three gpt
	time0 <- getCPUTime
	putStr $ concat ["Start: ",show $ to_ms_time time0, " mks\n"]
	putStr $ concat ["Number of colors: ",show number, "\n"]
	time1 <- getCPUTime
	putStr $ concat ["End: ",show $ to_ms_time time1, " mks\n"]
	--putStr $ concat ["Original graph:\n\n", graph_to_string $ if (num == 0) then dot_string_to_graph grStr else generate_random_graph num (fst $ next x), "\n"]
	--putStr $ concat ["Colored graph:\n\n", graph_to_string graph, "\n"]
	writeFile "trase.txt" trace
	putStr $ concat ["Coloring valid: ",show $ check_colors graph,"\n"]
	--putStr $ concat ["Number of colors: ",show number, "\n"]
	putStr $ concat ["Time: ", show $ to_ms_time $ (-) time1 time0, " mks\n"]
	writeFile outFile $ graph_to_dot_string $ graph
	
data Flag = Input String | Output String | Numb String

options :: [OptDescr Flag]
options = [
	Option ['i'] ["input"] (ReqArg Input "DOT FILE") "some option that requires a file argument",
    Option ['o'] ["output"] (ReqArg Output "DOT FILE") "some option that requires a file argument",
	Option ['n'] ["number"] (ReqArg Numb "VERTEX NUMBER") "some option that requires a file argument"
  ]